﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Orpheus.Analyzer
{
    public class NotePitchHelper
    {
        public static double GetNoteFrequency(Note note)
        {
            //double octaveFactor = note.Octave == 0 ? 1 : Math.Pow(2, Convert.ToInt32(note.Octave));
            //double noteFactor = Math.Pow(1.05946309, note.IndexInOctave); //Math.Pow(2, note.IndexInOctave/12.0);

            //double cOctave = Math.Round(16.35 * octaveFactor, 2);

            //return Math.Round(cOctave * noteFactor, 2);

            return NoteFrequences[note.IndexInOctave + Convert.ToInt32(note.Octave)*12];
        }

        public static Note GetNoteByFrequency(double frequency)
        {
            if (frequency <= 0)
            {
                throw new ArgumentException("Frequency must be greater then 0");
            }

            Func<int, Note> getNoteByIndex = i => new Note {IndexInOctave = i%12, Octave = (OctaveNames) (i/12)};

            int index = NoteFrequences.FindIndex(0, x => x > frequency);
            if (Math.Abs(NoteFrequences[index] - frequency) < Precision)
            {
                return getNoteByIndex(index);
            }

            int lessIndex = 0, moreIndex = 0;
            if (frequency < NoteFrequences[index])
            {
                if (index == 0)
                {
                    throw new ArgumentException();
                }

                lessIndex = index - 1;
                moreIndex = index;
            }

            if (frequency > NoteFrequences[index])
            {
                if (index == NoteFrequences.Count - 1)
                {
                    throw new ArgumentException();
                }

                lessIndex = index;
                moreIndex = index + 1;
            }

            return frequency/NoteFrequences[lessIndex] < NoteFrequences[moreIndex]/frequency
                       ? getNoteByIndex(lessIndex)
                       : getNoteByIndex(moreIndex);
        }

        public static double MaxPitch
        {
            get
            {
                return NoteFrequences.Max();
            }
        }

        public static double MinPitch
        {
            get
            {
                return NoteFrequences.Min();
            }
        }

        private const double Precision = 0.001;

        private static readonly List<double> NoteFrequences = new List<double>
            {
                16.352,
                17.324,
                18.354,
                19.445,
                20.602,
                21.827,
                23.125,
                24.500,
                25.957,
                27.500,
                29.135,
                30.868,

                32.703,
                34.648,
                36.708,
                38.891,
                41.203,
                43.654,
                46.249,
                48.999,
                51.913,
                55.000,
                58.270,
                61.735,

                65.406,
                69.296,
                73.416,
                77.782,
                82.407,
                87.307,
                92.499,
                97.999,
                103.83,
                110.00,
                116.54,
                123.47,


                130.81,
                138.59,
                146.83,
                155.56,
                164.81,
                174.61,
                185.00,
                196.00,
                207.65,
                220.00,
                233.08,
                246.94,

                261.63,
                277.18,
                293.66,
                311.13,
                329.63,
                349.23,
                369.99,
                392.00,
                415.30,
                440.00,
                466.16,
                493.88,

                523.25,
                554.37,
                587.33,
                622.25,
                659.26,
                698.46,
                739.99,
                783.99,
                830.61,
                880.00,
                932.33,
                987.77,

                1046.5,
                1108.7,
                1174.7,
                1244.5,
                1318.5,
                1396.9,
                1480.0,
                1568.0,
                1661.2,
                1760.0,
                1864.7,
                1975.5,

                2093.0,
                2217.5,
                2349.3,
                2489.0,
                2637.0,
                2793.8,
                2960.0,
                3136.0,
                3322.4,
                3520.0,
                3729.3,
                3951.1,

                4186.0,
                4434.9,
                4698.6,
                4978.0,
                5274.0,
                5587.7,
                5919.9,
                6271.9,
                6644.9,
                7040.0,
                7458.6,
                7902.1

            };


        //private static readonly List<double> NoteFrequences = new List<double>
        //    {
        //        16.35,
        //        17.32,
        //        18.35,
        //        19.45,
        //        20.60,
        //        21.83,
        //        23.12,
        //        24.50,
        //        25.96,
        //        27.50,
        //        29.14,
        //        30.87,
        //        32.70,
        //        34.65,
        //        36.71,
        //        38.89,
        //        41.20,
        //        43.65,
        //        46.25,
        //        49.00,
        //        51.91,
        //        55.00,
        //        58.27,
        //        61.74,
        //        65.41,
        //        69.30,
        //        73.42,
        //        77.78,
        //        82.41,
        //        87.31,
        //        92.50,
        //        98.00,
        //        103.83,
        //        110.00,
        //        116.54,
        //        123.47,
        //        130.81,
        //        138.59,
        //        146.83,
        //        155.56,
        //        164.81,
        //        174.61,
        //        185.00,
        //        196.00,
        //        207.65,
        //        220.00,
        //        233.08,
        //        246.94,
        //        261.63,
        //        277.18,
        //        293.66,
        //        311.13,
        //        329.63,
        //        349.23,
        //        369.99,
        //        392.00,
        //        415.30,
        //        440.00,
        //        466.16,
        //        493.88,
        //        523.25,
        //        554.37,
        //        587.33,
        //        622.25,
        //        659.26,
        //        698.46,
        //        739.99,
        //        783.99,
        //        830.61,
        //        880.00,
        //        932.33,
        //        987.77,
        //        1046.50,
        //        1108.73,
        //        1174.66,
        //        1244.51,
        //        1318.51,
        //        1396.91,
        //        1479.98,
        //        1567.98,
        //        1661.22,
        //        1760.00,
        //        1864.66,
        //        1975.53,
        //        2093.00,
        //        2217.46,
        //        2349.32,
        //        2489.02,
        //        2637.02,
        //        2793.83,
        //        2959.96,
        //        3135.96,
        //        3322.44,
        //        3520.00,
        //        3729.31,
        //        3951.07,
        //        4186.01,
        //        4434.92,
        //        4698.64,
        //        4978.03
        //    };
    }
}
